from abc import ABCMeta, abstractmethod

# 装饰器引入
class Person(metaclass=ABCMeta):
    '''人'''
    def __init__(self, name):
        self._name = name

    @abstractmethod
    def wear(self):
        print("着装：")


class Engineer(Person):
    def __init__(self, name, skill):
        super().__init__(name)
        self.__skill = skill

    def wear(self):
        print(f"我是 {self.__skill}工程师 {self._name}", end=", ")
        super().wear()


class Teacher(Person):
    def __init__(self, name, title):
        super().__init__(name)
        self.___title = title

    def getTitle(self):
        return self.__title

    def wear(self):
        print(f"我是 {self._name}{self.getTitle()}", end=", ")
        super().wear()


class ClothingDecorator(Person):
    '''服装装饰器的基类'''
    def __init__(self, person):
        self._decorated = person

    def wear(self):
        self._decorated.wear()
        self.decorate()

    @abstractmethod
    def decorate(self):
        pass

class CasualPantDecorator(ClothingDecorator):
    def __init__(self, person):
        super().__init__(person)

    def decorate(self):
        print("一条橙色的休闲裤")


class BeltDecorator(ClothingDecorator):
    def __init__(self, person):
        super().__init__(person)

    def decorate(self):
        print("一条银色针扣头的皮带")

class LeatherShoesDecorator(ClothingDecorator):
    def __init__(self, person):
        super().__init__(person)

    def decorate(self):
        print("一条深色休闲皮鞋")


def testDecorator():
    # tony = Engineer("Tony", "后端")
    # pant = CasualPantDecorator(tony)
    # belt = BeltDecorator(pant)
    # shoes = LeatherShoesDecorator(belt)
    shoes = LeatherShoesDecorator(BeltDecorator(CasualPantDecorator(Engineer("Tony", "后端"))))
    shoes.wear()


# 1、装饰器:函数装饰函数装饰函数
def log(func):
    def inner(*args, **kwargs):
        print(f"start call {func.__name__}")
        res = func(*args, **kwargs)
        print(f"end call {func.__name__}")
        return res
    return inner


@log
def hello(num):
    for i in range(num):
        print(f"Hello {i}")

# hello = log(hello)
# hello == log.inner True
# hello(20)


# 2、装饰器：函数装饰类，实现单例模式
def singleton(cls):
    # 必须是可变变量，否则
    instances = []
    def inner(*args, **kwargs):
        if not instances:
            instances.append(cls(*args, **kwargs))
            return instances[0]
        return instances[0]
    return inner


@singleton
class Foo:
    def __init__(self, name):
        self._name = name

    def show(self):
        print(self._name)

# Foo = singleton(Foo)

# f1 = Foo("Foo1")

# f2 = Foo("Foo2")

# f1.show(), f2.show()

# 3、类装饰类:必须实现call方法
class Singleton:
    def __init__(self, cls):
        self._class = cls
        self._instance = None

    def __call__(self, *args, **kwargs):
        if self._instance:
            return self._instance
        else:
            self._instance = self._class(*args, **kwargs)
            return self._instance

@Singleton
class Bar:
    def __init__(self, name):
        self._name = name

    def show(self):
        print(self._name)

# Bar = Singleton(Bar)

# bar = Bar("bar1")

# bar.show()

# 4、带参数的装饰器：日志装饰器：只被调用指定次

def log(times):
    # 必须是可变类型，否则当下面在改变其值的时候，地址就会发生变化，显示未定义错误
    temps = []
    temps.append(times)
    def outer(func):
        def inner(*args, **kwargs):
            if temps[0] > 0:
                print(f"start call {func.__name__}")
                temps[0] = temps[0] - 1
                res = func(*args, **kwargs)
                print(f"end call {func.__name__}")
            else:
                res = func(*args, **kwargs)
            return res
        return inner
    return outer


@log(20)
def do(string):
    print(f"我正在{string}")

for i in range(30):
    do("洗碗")






